#ifdef SU1
#define _GLIBCXX_DEBUG
#endif

#include <algorithm>
#include <bitset>
#include <cassert>
#include <climits>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cmath>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <stack>
#include <set>
#include <string>
#include <utility>
#include <vector>

using namespace std;

#define forn(i, n) for (int i = 0; i < int(n); i++)
#define forl(i, n) for (int i = 1; i <= int(n); i++)
#define ford(i, n) for (int i = int(n) - 1; i >= 0; i--)
#define fore(i, l, r) for (int i = int(l); i <= int(r); i++)
#define pb(a) push_back(a)
#define mp(x, y) make_pair((x), (y))
#define sz(a) (int) (a).size()
#define all(a) (a).begin(), (a).end()
#define ft first
#define sc second
#define x first
#define y second

template<typename X> inline X abs(const X& a) { return a < 0 ? -a : a; }
template<typename X> inline X sqr(const X& a) { return a * a; }

typedef long long li;
typedef long double ld;
typedef pair<int, int> pt;

const int INF = int(2e9) + 300;
const li INF64 = li(1e18);
const ld PI = acosl(ld(-1));
const ld EPS = 1e-9;

const int N = 20500;
int n, m;
vector<pair<pt,int> > g[N];

inline bool read()
{
	assert(scanf("%d%d", &n, &m) == 2);
	forn(i, m) {
		int a, b, w;
		assert(scanf("%d%d%d", &a, &b, &w) == 3);
		a--; b--;
		g[a].pb(mp(pt(b, w), i));
		g[b].pb(mp(pt(a, w), i));
	}
	return true;
}

vector<pt> g2[N];

vector<int> ans;

bool used[N];
int tin[N], fup[N], curt = 0;
int d[N];

void dfs(int v, int pe = -1) {
	tin[v] = fup[v] = curt++;
	forn(i, sz(g2[v])) {
		int to = g2[v][i].x;
		if (g2[v][i].y == pe) continue;
		if (used[to])
			fup[v] = min(fup[v], tin[to]);
		else {
			used[to] = true;
			dfs(to, g2[v][i].y);
//			cerr << v + 1 << ' ' << to + 1 << ' ' << fup[to] << ' ' << tin[v] << endl;
			if (fup[to] > tin[v]) {
				ans.pb(g2[v][i].y);
			}
			fup[v] = min(fup[v], fup[to]);
		}
	}
}

void dex(int v, int d[N]) {
	forn(i, n)
		d[i] = INF;
	set<pt> q;
	d[v] = 0;
	q.insert(pt(0, v));
	while (!q.empty()) {
		int v = q.begin()->y;
		q.erase(q.begin());
		forn(i, sz(g[v])) {
			int to = g[v][i].x.x, cost = g[v][i].x.y;
			if (d[to] > d[v] + cost) {
				q.erase(pt(d[to], to));
				d[to] = d[v] + cost;
				q.insert(pt(d[to], to));
			}
		}
	}
}

int d2[N];
inline void solve()
{
	dex(0, d);
	dex(n - 1, d2);
	forn(v, n) {
		forn(i, sz(g[v])) {
			int to = g[v][i].x.x, cost = g[v][i].x.y;
			if (d[v] + cost + d2[to] == d[n - 1]) {
				g2[v].pb(pt(to, g[v][i].y));
				g2[to].pb(pt(v, g[v][i].y));
				//cerr << v + 1 << ' ' << to + 1 << endl;
			}
		}
	}
	used[0] = true;
	dfs(0);
	printf("%d\n", sz(ans));
	sort(all(ans));
	forn(i, sz(ans)) {
		if (i) putchar(' ');
		printf("%d", ans[i] + 1);
	}
	puts("");
}

int main()
{
#ifdef SU1
	assert(freopen("input.txt", "rt", stdin));
//	assert(freopen("output.txt", "wt", stdout));
#endif

	cout << fixed << setprecision(10);
	cerr << fixed << setprecision(5);

	assert(read());
	solve();
	
#ifdef SU1
	cerr << "=== TIME : " << clock() << " ===" << endl;
#endif
	return 0;
}
